﻿/****************************************************************************
 * 工    具：  HK_TargetCam
 *
 * 描    述：  HK_TargetCam 是一套多功能的摄像机多目标管理系统，提供灵活的相机控制方案，支持多种目标类型，可根据目标类型进行相机切换，主要功能如下：
 *
 *            多目标切换，各目标类型及切换效果如下：
 *            RotTarget：控制 Camera 围绕 Target 旋转、缩放，并可设置旋转边界。
 *            AreaTarget：在 Target 设定的区域内，实现 Camera 的自由平移与缩放。
 *            FollowTarget：Camera 跟随 Target 移动，同时支持围绕 Target 的旋转与缩放。
 *            BirdViewTarget：在 Target 设定区域内，提供 Camera 的俯仰与缩放控制，并切换至正交视角。
 *
 *            运行时控制功能：
 *            通过 Command 指令，可进行切换目标。
 *            通过 Command 指令切换目标时，可配置以下参数：
 *                 Camera 缩放速度
 *                 Camera 移动速度
 *                 俯仰角限制
 *                 目标切换动画时间
 *                 是否冻结操控
 *            通过 Event 事件，可订阅目标切换开始/完成事件。
 *            通过 Query 查询指令，可查询当前目标。
 *            支持闪现/眨眼效果的目标切换。
 *            支持可视化编辑，可在 Scene 视窗中进行目标编辑。
 *
 * 版    本：  V1.7
 * 作    者：  京产肠饭、谭潇杰
 * 
 * 创    建：  2023/04/19  V1.0
 * 
 * 更    新：  2024/10/06  V1.1
 *            1.代码优化：优化 IHK_TargetCamSystem 系统层代码组织结构
 *            2.Bug修复：修复 TargetEnum 唯一性检测失败的Bug
 *            
 *            2024/10/08  V1.2
 *            1.性能优化：优化 HK_TargetCamera 性能，移除 LateUpdate 中 GetType() 的循环调用，减少性能开销
 *            
 *            2024/10/12  V1.3
 *            1.Bug修复：修复 Target_List 不及时刷新的问题
 *            2.Bug修复：枚举体判断结尾是否有英文逗号，根据情况进行添加及格式化
 *            3.功能新增：在场景中的 Target 的 Inspector 面板中，新增了一个按钮。
 *                      实现根据物体名称动态添加新的 TargetType 类型。通过此功能，可方便扩展 TargetType 枚举，提升灵活性和效率。 
 *                      
 *            2024/10/23  V1.4
 *            1.功能优化：通过 ActionKit.ScreenTransition 实现眨眼效果，移除Mask物体，减少不同渲染管线的适配工作
 *            
 *            2024/11/16  V1.5
 *            1.功能新增：新增 CMD_SetFreezeMode 指令，可设置TargetCam的是否冻结
 *            
 *            2025/02/01  V1.6
 *            1.Bug修复：修复根据物体名称，添加 Target 类型失败的Bug。
 *            2.功能新增：新增正交视角的 BirdViewTarget，切换后相机将俯视并切换为正交，实现场景的鸟瞰视图。
 *            3.性能优化：重构代码。
 *
 *            2025/03/06  V1.7
 *            1.功能新增：新增 Query_GetCurrentTarget，可获取当前相机的目标类型
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*****************************************************************************/

using System.Collections.Generic;
using DG.Tweening;
using QFramework;
using UnityEngine;

namespace HKTools
{
    public interface IHK_TargetCamSystem : ISystem
    {
        /// <summary>
        /// 是否正在切换目标中
        /// </summary>
        bool IsChangingTarget { get; set; }

        /// <summary>
        /// 是否冻结 Camera
        /// </summary>
        bool IsFreezeCam { get; set; }

        /// <summary>
        /// 当前的 Target
        /// </summary>
        HK_BaseTarget CurTarget { get; set; }

        /// <summary>
        /// 初始化被控制的 Camera
        /// </summary>
        void InitCamera(HK_TargetCamera targetCamera);

        /// <summary>
        /// 初始化 CamTarget列表
        /// </summary>
        void InitCamTargetList(HK_BaseTarget targetItem);

        /// <summary>
        /// 从 CamTarget列表 移除
        /// </summary>
        void RemoveFromCamTargetList(HK_BaseTarget targetItem);

        /// <summary>
        /// 设置默认的 MoveSpeed和ZoomSpeed
        /// </summary>
        void SetMoveAndZoomSpeed(float moveSpeed, float zoomSpeed);

        /// <summary>
        /// 设置俯仰角
        /// </summary>
        void SetPitchAngle(float minAngle, float maxAngle);

        /// <summary>
        /// 改变 CamTarget
        /// </summary>
        void ChangeTarget(HK_TargetEnum targetType, bool isFlash, bool isBlink);

        /// <summary>
        /// 设置 TargetCam 冻结状态
        /// </summary>
        void SetFreezeMode(bool isFreeze);

        /// <summary>
        /// 设置切换目标的时间
        /// </summary>
        void SetTargetChangeTime(float targetChangeTime);
    }

    public class HK_TargetCamSystem : AbstractSystem, IHK_TargetCamSystem
    {
        /// <summary>
        /// 是否正在切换目标中
        /// </summary>
        public bool IsChangingTarget { get; set; }

        /// <summary>
        /// 是否冻结 Camera
        /// </summary>
        public bool IsFreezeCam { get; set; }

        /// <summary>
        /// 当前的 Target
        /// </summary>
        public HK_BaseTarget CurTarget { get; set; }

        // 当前控制的 TargetCamera
        HK_TargetCamera CtrlCam { get; set; }

        // Targets 列表
        List<HK_BaseTarget> Target_List { get; set; }

        // 切换Target的时间
        float DefaultTargetChangeTime { get; set; }

        float curTargetChangeTime;

        float blinkTime = 0.4f;
        IActionController blinkActionController = null;

        protected override void OnInit()
        {
            IsChangingTarget = false;
            IsFreezeCam = false;
            DefaultTargetChangeTime = 0.8f;
            curTargetChangeTime = DefaultTargetChangeTime;
            Target_List = new List<HK_BaseTarget>();

            HKDebug.Log("IHK_TargetCamSystem 初始化完成!", LogColor.Cyan, LogStyle.Bold);
        }

        /// <summary>
        /// 初始化 被控制的 Camera
        /// </summary>
        public void InitCamera(HK_TargetCamera targetCam)
        {
            this.CtrlCam = targetCam;
        }

        /// <summary>
        /// 初始化 CamTarget列表
        /// </summary>
        public void InitCamTargetList(HK_BaseTarget targetItem)
        {
            if (!Target_List.Contains(targetItem))
            {
                Target_List.Add(targetItem);
            }
        }

        /// <summary>
        /// 从 CamTarget列表 移除
        /// </summary>
        public void RemoveFromCamTargetList(HK_BaseTarget targetItem)
        {
            if (Target_List.Contains(targetItem))
            {
                Target_List.Remove(targetItem);
            }
        }

        /// <summary>
        /// 设置默认的 MoveSpeed和ZoomSpeed
        /// </summary>
        public void SetMoveAndZoomSpeed(float moveSpeed, float zoomSpeed)
        {
            CtrlCam.SetMoveAndZoomSpeed(moveSpeed, zoomSpeed);
        }

        /// <summary>
        /// 设置俯仰角
        /// </summary>
        public void SetPitchAngle(float minAngle, float maxAngle)
        {
            CtrlCam.SetPitchAngle(minAngle, maxAngle);
        }

        /// <summary>
        /// 改变 CamTarget
        /// </summary>
        public void ChangeTarget(HK_TargetEnum targetType, bool isFlash, bool isBlink)
        {
            // 使用LINQ查找目标
            HK_BaseTarget newTarget = Target_List.Find(target => target.targetType == targetType);

            // 如果目标不存在或是当前目标，直接返回
            if (newTarget == null || newTarget == CurTarget)
            {
                HKDebug.LogWarning("未找到相应的 Target！");
                return;
            }

            if (isFlash)
            {
                curTargetChangeTime = 0;
                if (isBlink)
                    blinkTime = 0.4f;
                else
                    blinkTime = 0f;
            }
            else
            {
                curTargetChangeTime = DefaultTargetChangeTime;
                blinkTime = 0f;
            }

            if (blinkTime == 0.4f)
            {
                if (blinkActionController != null)
                    blinkActionController.Deinit();

                blinkActionController = ActionKit.ScreenTransition
                  .FadeInOut()
                  .In(fadeIn => fadeIn.Duration(blinkTime))
                  .OnInFinish(() => PlayCameraMoveAnim(newTarget))
                  .Out(fadeOut => fadeOut.Duration(blinkTime))
                  .StartGlobal();
            }
            else
            {
                PlayCameraMoveAnim(newTarget);
            }
        }

        /// <summary>
        /// 设置 TargetCam 冻结状态
        /// </summary>
        public void SetFreezeMode(bool isFreeze)
        {
            IsFreezeCam = isFreeze;
        }

        /// <summary>
        /// 设置切换目标的时间
        /// </summary>
        public void SetTargetChangeTime(float targetChangeTime)
        {
            DefaultTargetChangeTime = targetChangeTime;
        }

        /// <summary>  
        /// 播放 切换目标的运动动画  
        /// </summary>  
        void PlayCameraMoveAnim(HK_BaseTarget newTarget)
        {
            Camera camera = CtrlCam.GetComponent<Camera>();

            if (camera.fieldOfView != newTarget.FOV)
            {
                camera.DOFieldOfView(newTarget.FOV, curTargetChangeTime);
            }

            Quaternion lookAtRot;
            Vector3 resultEuler = Vector3.zero;
            Vector3 targetPos = Vector3.zero;

            // 根据目标类型播放相应的动画 
            switch (newTarget)
            {
                case HK_RotTarget rotTarget:
                    lookAtRot = Quaternion.LookRotation(rotTarget.TargetDir, rotTarget.transform.up);
                    resultEuler = lookAtRot.eulerAngles;
                    targetPos = rotTarget.TargetPos;
                    break;
                case HK_AreaTarget areaTarget:
                    lookAtRot = Quaternion.LookRotation(areaTarget.TargetDir);
                    resultEuler = lookAtRot.eulerAngles;
                    targetPos = areaTarget.TargetPos;
                    break;
                case HK_FollowTarget followTarget:
                    lookAtRot = Quaternion.LookRotation(followTarget.TargetDir, followTarget.transform.up);
                    resultEuler = lookAtRot.eulerAngles;
                    targetPos = followTarget.TargetPos;
                    break;
                case HK_BirdViewTarget birdViewTarget: // ++
                    lookAtRot = Quaternion.LookRotation(birdViewTarget.TargetDir, birdViewTarget.transform.forward);
                    resultEuler = lookAtRot.eulerAngles;
                    targetPos = birdViewTarget.TargetPos;
                    break;
            }

            CtrlCam.transform.DORotate(resultEuler, curTargetChangeTime);

            CtrlCam.transform.DOMove(targetPos, curTargetChangeTime)
                .OnPlay(() =>
                {
                    // 发送 开始切换 Target 事件
                    this.SendEvent(new Event_SwitchTargetBegin()
                    {
                        _targetEnum = newTarget.targetType
                    });
                    IsChangingTarget = true;
                })
                .OnComplete(() =>
                {
                    IsChangingTarget = false;

                    // 发送 完成切换 Target 事件
                    this.SendEvent(new Event_SwitchTargetEnd()
                    {
                        _targetEnum = newTarget.targetType
                    });
                });

            CurTarget = newTarget;

            if (newTarget is HK_RotTarget)
            {
                CtrlCam.OnSwitchToRotTarget(newTarget as HK_RotTarget);
            }
            else if (newTarget is HK_AreaTarget)
            {
                CtrlCam.OnSwitchToAreaTarget(newTarget as HK_AreaTarget);
            }
            else if (newTarget is HK_FollowTarget)
            {
                CtrlCam.OnSwitchToFollowTarget(newTarget as HK_FollowTarget);
            }
            else if (newTarget is HK_BirdViewTarget)
            {
                CtrlCam.OnSwitchToBirdViewTarget(newTarget as HK_BirdViewTarget);
            }
        }
    }
}